package handlers

import (
    "net/http"
    "strconv"

    "github.com/gin-gonic/gin"

    "github.com/samaa/photosalesplus/backend/internal/services"
    "github.com/samaa/photosalesplus/backend/internal/storage"
)

type ProductHandler struct {
	service services.ProductService
}

func NewProductHandler(service services.ProductService) *ProductHandler {
	return &ProductHandler{service: service}
}

type productWriteRequest struct {
    Title       string   `json:"title" binding:"required"`
    Type        string   `json:"type" binding:"required"`
    Description string   `json:"description"`
    Price       float64  `json:"price" binding:"required"`
    CoverAssetID *uint   `json:"cover_asset_id"`
    FreePreviewLimit int `json:"free_preview_limit"`
    Images      []struct {
        AssetID   uint `json:"asset_id" binding:"required"`
        SortOrder int  `json:"sort_order"`
        IsPreview bool `json:"is_preview"`
    } `json:"images"`
    IsPublished *bool    `json:"is_published"`
}

func (h *ProductHandler) List(c *gin.Context) {
	search := c.Query("search")
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))

	var publishedFilter *bool
	if raw := c.Query("published"); raw != "" {
		value, err := strconv.ParseBool(raw)
		if err != nil {
			c.JSON(http.StatusBadRequest, APIResponse{Error: "invalid published value"})
			return
		}
		publishedFilter = &value
	}

    products, total, err := h.service.List(c.Request.Context(), search, publishedFilter, page, pageSize)
    if err != nil {
        respondError(c, http.StatusInternalServerError, err)
        return
    }

    // Map URLs for assets
    out := make([]gin.H, 0, len(products))
    for _, p := range products {
        images := make([]gin.H, 0, len(p.Images))
        for _, img := range p.Images {
            var asset gin.H
            if img.Asset != nil {
                asset = gin.H{
                    "id":             img.Asset.ID,
                    "original_path":  img.Asset.OriginalPath,
                    "preview_path":   img.Asset.PreviewPath,
                    "thumb_path":     img.Asset.ThumbPath,
                    "original_url":   storage.BuildURL(img.Asset.OriginalPath),
                    "preview_url":    storage.BuildURL(img.Asset.PreviewPath),
                    "thumb_url":      storage.BuildURL(img.Asset.ThumbPath),
                    "mime_type":      img.Asset.MimeType,
                    "width":          img.Asset.Width,
                    "height":         img.Asset.Height,
                    "preview_width":  img.Asset.PreviewWidth,
                    "preview_height": img.Asset.PreviewHeight,
                    "thumb_width":    img.Asset.ThumbWidth,
                    "thumb_height":   img.Asset.ThumbHeight,
                }
            }
            images = append(images, gin.H{
                "id":         img.ID,
                "sort_order": img.SortOrder,
                "is_preview": img.IsPreview,
                "asset_id":   img.AssetID,
                "asset":      asset,
            })
        }

        var cover gin.H
        if p.CoverAsset != nil {
            cover = gin.H{
                "id":            p.CoverAsset.ID,
                "original_path": p.CoverAsset.OriginalPath,
                "preview_path":  p.CoverAsset.PreviewPath,
                "thumb_path":    p.CoverAsset.ThumbPath,
                "original_url":  storage.BuildURL(p.CoverAsset.OriginalPath),
                "preview_url":   storage.BuildURL(p.CoverAsset.PreviewPath),
                "thumb_url":     storage.BuildURL(p.CoverAsset.ThumbPath),
            }
        }

        out = append(out, gin.H{
            "id":                p.ID,
            "title":             p.Title,
            "type":              p.Type,
            "description":       p.Description,
            "price":             p.Price,
            "cover_asset_id":    p.CoverAssetID,
            "cover_asset":       cover,
            "free_preview_limit": p.FreePreviewLimit,
            "is_published":      p.IsPublished,
            "created_at":        p.CreatedAt,
            "updated_at":        p.UpdatedAt,
            "images":            images,
            "orders_count":      p.OrdersCount,
            "units_sold":        p.UnitsSold,
            "total_revenue":     p.TotalRevenue,
        })
    }

    meta := gin.H{
        "page":      page,
        "page_size": pageSize,
        "total":     total,
    }
    respondSuccess(c, out, meta)
}

func (h *ProductHandler) Get(c *gin.Context) {
	idVal, err := strconv.Atoi(c.Param("id"))
	if err != nil || idVal <= 0 {
		c.JSON(http.StatusBadRequest, APIResponse{Error: "invalid product id"})
		return
	}

    product, err := h.service.Get(c.Request.Context(), uint(idVal))
    if err != nil {
        respondError(c, http.StatusNotFound, err)
        return
    }

    // Map single product with URLs
    images := make([]gin.H, 0, len(product.Images))
    for _, img := range product.Images {
        var asset gin.H
        if img.Asset != nil {
            asset = gin.H{
                "id":             img.Asset.ID,
                "original_path":  img.Asset.OriginalPath,
                "preview_path":   img.Asset.PreviewPath,
                "thumb_path":     img.Asset.ThumbPath,
                "original_url":   storage.BuildURL(img.Asset.OriginalPath),
                "preview_url":    storage.BuildURL(img.Asset.PreviewPath),
                "thumb_url":      storage.BuildURL(img.Asset.ThumbPath),
                "mime_type":      img.Asset.MimeType,
                "width":          img.Asset.Width,
                "height":         img.Asset.Height,
                "preview_width":  img.Asset.PreviewWidth,
                "preview_height": img.Asset.PreviewHeight,
                "thumb_width":    img.Asset.ThumbWidth,
                "thumb_height":   img.Asset.ThumbHeight,
            }
        }
        images = append(images, gin.H{
            "id":         img.ID,
            "sort_order": img.SortOrder,
            "is_preview": img.IsPreview,
            "asset_id":   img.AssetID,
            "asset":      asset,
        })
    }
    var cover gin.H
    if product.CoverAsset != nil {
        cover = gin.H{
            "id":            product.CoverAsset.ID,
            "original_path": product.CoverAsset.OriginalPath,
            "preview_path":  product.CoverAsset.PreviewPath,
            "thumb_path":    product.CoverAsset.ThumbPath,
            "original_url":  storage.BuildURL(product.CoverAsset.OriginalPath),
            "preview_url":   storage.BuildURL(product.CoverAsset.PreviewPath),
            "thumb_url":     storage.BuildURL(product.CoverAsset.ThumbPath),
        }
    }
    respondSuccess(c, gin.H{
        "id":                product.ID,
        "title":             product.Title,
        "type":              product.Type,
        "description":       product.Description,
        "price":             product.Price,
        "cover_asset_id":    product.CoverAssetID,
        "cover_asset":       cover,
        "free_preview_limit": product.FreePreviewLimit,
        "is_published":      product.IsPublished,
        "created_at":        product.CreatedAt,
        "updated_at":        product.UpdatedAt,
        "images":            images,
    }, nil)
}

func (h *ProductHandler) Create(c *gin.Context) {
	var req productWriteRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, APIResponse{Error: err.Error()})
		return
	}

    imgs := make([]services.ProductImageInput, 0, len(req.Images))
    for _, i := range req.Images {
        imgs = append(imgs, services.ProductImageInput{
            AssetID:   i.AssetID,
            SortOrder: i.SortOrder,
            IsPreview: i.IsPreview,
        })
    }
    payload := services.ProductPayload{
        Title:       req.Title,
        Type:        req.Type,
        Description: req.Description,
        Price:       req.Price,
        CoverAssetID: req.CoverAssetID,
        FreePreviewLimit: req.FreePreviewLimit,
        Images:      imgs,
        IsPublished: req.IsPublished,
    }

	product, err := h.service.Create(c.Request.Context(), payload)
	if err != nil {
		respondError(c, http.StatusInternalServerError, err)
		return
	}

	respondCreated(c, product)
}

func (h *ProductHandler) Update(c *gin.Context) {
	idVal, err := strconv.Atoi(c.Param("id"))
	if err != nil || idVal <= 0 {
		c.JSON(http.StatusBadRequest, APIResponse{Error: "invalid product id"})
		return
	}

	var req productWriteRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, APIResponse{Error: err.Error()})
		return
	}

    imgs := make([]services.ProductImageInput, 0, len(req.Images))
    for _, i := range req.Images {
        imgs = append(imgs, services.ProductImageInput{
            AssetID:   i.AssetID,
            SortOrder: i.SortOrder,
            IsPreview: i.IsPreview,
        })
    }
    payload := services.ProductPayload{
        Title:       req.Title,
        Type:        req.Type,
        Description: req.Description,
        Price:       req.Price,
        CoverAssetID: req.CoverAssetID,
        FreePreviewLimit: req.FreePreviewLimit,
        Images:      imgs,
        IsPublished: req.IsPublished,
    }

	product, err := h.service.Update(c.Request.Context(), uint(idVal), payload)
	if err != nil {
		respondError(c, http.StatusInternalServerError, err)
		return
	}

	respondSuccess(c, product, nil)
}

func (h *ProductHandler) Delete(c *gin.Context) {
	idVal, err := strconv.Atoi(c.Param("id"))
	if err != nil || idVal <= 0 {
		c.JSON(http.StatusBadRequest, APIResponse{Error: "invalid product id"})
		return
	}

	if err := h.service.Delete(c.Request.Context(), uint(idVal)); err != nil {
		respondError(c, http.StatusInternalServerError, err)
		return
	}

	c.JSON(http.StatusOK, APIResponse{Message: "删除成功"})
}

func (h *ProductHandler) UpdatePublishStatus(c *gin.Context) {
	idVal, err := strconv.Atoi(c.Param("id"))
	if err != nil || idVal <= 0 {
		c.JSON(http.StatusBadRequest, APIResponse{Error: "invalid product id"})
		return
	}

	var req struct {
		IsPublished bool `json:"is_published"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, APIResponse{Error: err.Error()})
		return
	}

	if err := h.service.UpdatePublishStatus(c.Request.Context(), uint(idVal), req.IsPublished); err != nil {
		respondError(c, http.StatusInternalServerError, err)
		return
	}

	respondSuccess(c, gin.H{
		"id":           idVal,
		"is_published": req.IsPublished,
	}, nil)
}
